/***********************************************************************************
    Filename: CC1100.c

    Copyright 2007 Texas Instruments, Inc.
***********************************************************************************/
#include  "board.h"
#include  "Typedef.h"
#include  "macros.h"
#include  "hal_int.h"
#include  "hal_mcu.h"
#include  "hal_ext_int.h"
#include  "hal_IO_Spi.h"
#include  "CC1100.h"
#include  "CC1100_hal_rf.h"
#include  "CC1100_RF_Setting.h"

#include  "Phy_Frame.h"

#define   CC1100_ASSERT(x)    ASSERT(x)

INT8U CC1100_PaTable[] = {CC1100_TX_PA_0DBM};
INT8U CC1100_PaTableLth = 1;


//----------------------------------------------------------------------------------
//  Constants used in this file
//----------------------------------------------------------------------------------



#define CC1100_MAX_PACKET_SIZE          PHY_FRAME_MAX_SIZE


#define CC1100_GDO0_INT    HAL_AVR_INT1

/* GDO functionality */
#define CC1100_GDO_SYNC           6
#define CC1100_GDO_CCA            9
#define CC1100_GDO_PA_PD          27  /* low when transmit is active, low during sleep */
#define CC1100_GDO_LNA_PD         28  /* low when receive is active, low during sleep */
#define CC1100_GDO_CS             0x0E

#define CC1100_RSSI_OFFSET                     79   /* no units */
#define CC1100_RANDOM_OFFSET                   67
#define CC1100_RANDOM_MULTIPLIER              109

/* Worst case wait period in RX state before RSSI becomes valid.
  * These numbers are from Design Note DN505 with added safety margin.
  */
#define CC1100_RSSI_VALID_DELAY_US    1300
#define CC1100_BACKOFF_PERIOD_USECS   250

/* Main Radio Control State Machine control configuration:
 * - Remain RX state after RX
 * - Go to IDLE after TX
 * - RSSI below threshold and NOT receiving.
 */
#define CC1100_SETTING_MCSM1      0x3C
//#define CC1100_SETTING_MCSM1      0x3F
/* Max time we can be in a critical section within the delay function.
 * This could be fine-tuned by observing the overhead is calling the bsp delay
 * function. The overhead should be very small compared to this value.
 * Note that the max value for this must be less than 19 usec with the
 * default CLKCON.TICKSPD and CLKCON.CLOCKSPD settings and external 26 MHz
 * crystal as a clock source (which we use).
 *
 * Be careful of direct calls to CC1100_DelayUsec().
 */
#define CC1100_MAX_DELAY_US    16 /* usec */
#define CC1100_CCA_TRY_LIMIT   200

#define CC1100_PKTSTATUS_CCA   BV(4)
#define CC1100_PKTSTATUS_CS    BV(6)


#define CC1100_CONFIG_GDO0_PIN_AS_INPUT()             MCU_IO_INPUT(CC1100_GDO0_PORT,CC1100_GDO0_PIN)
#define CC1100_SYNC_PIN_IS_HIGH()                     MCU_IO_GET(CC1100_GDO0_PORT,CC1100_GDO0_PIN)
#define CC1100_ENABLE_SYNC_PIN_INT()                  halExtIntEnable(CC1100_GDO0_INT)
#define CC1100_DISABLE_SYNC_PIN_INT()                 halExtIntDisable(CC1100_GDO0_INT)
#define CC1100_SYNC_PIN_INT_IS_ENABLED()              halExtIntIsEnable(CC1100_GDO0_INT)
#define CC1100_CLEAR_SYNC_PIN_INT_FLAG()              halExtIntClear(CC1100_GDO0_INT)
#define CC1100_SYNC_PIN_INT_FLAG_IS_SET()             halExtIntGetFlag(CC1100_GDO0_INT)
#define CC1100_CONFIG_SYNC_PIN_FALLING_EDGE_INT()     halExtIntSetType(CC1100_GDO0_INT,HAL_EXT_INT_FALLING_EDGE)


#define CC1100_PAPD_PIN_IS_HIGH()                     CC1100_SYNC_PIN_IS_HIGH()
#define CC1100_CLEAR_PAPD_PIN_INT_FLAG()              CC1100_CLEAR_SYNC_PIN_INT_FLAG()
#define CC1100_PAPD_INT_FLAG_IS_SET()                 CC1100_SYNC_PIN_INT_FLAG_IS_SET()
#define CC1100_CONFIG_PAPD_FALLING_EDGE_INT()         CC1100_CONFIG_SYNC_PIN_FALLING_EDGE_INT()

#define CC1100_CONFIG_GDO0_AS_PAPD_SIGNAL()           CC1100_halRfWriteReg(CC1100_IOCFG0, CC1100_GDO_PA_PD)
#define CC1100_CONFIG_GDO0_AS_SYNC_SIGNAL()           CC1100_halRfWriteReg(CC1100_IOCFG0, CC1100_GDO_SYNC)


#define CC1100_CONFIG_GDO2_PIN_AS_INPUT()             MCU_IO_INPUT(CC1100_GDO2_PORT,CC1100_GDO2_PIN)
#define CC1100_CONFIG_GDO2_AS_CS_SIGNAL()             CC1100_halRfWriteReg(CC1100_IOCFG2, CC1100_GDO_CS)
#define CC1100_CS_PIN_IS_HIGH()                       MCU_IO_GET(CC1100_GDO2_PORT,CC1100_GDO2_PIN)


#define CC1100_STROBE_IDLE_AND_WAIT()                   \
{                                                     \
  CC1100_halRfStrobe( CC1100_SIDLE );                          \
  while (CC1100_halRfStrobe( CC1100_SNOP ) & 0xF0) ;           \
}

/* There is no bit in h/w to tell if RSSI in the register is valid or not.
 * The hardware needs to be in RX state for a certain amount of time before
 * a valid RSSI value is calculated and placed in the register. This min
 * wait time is defined by CC1100_BOARD_RSSI_VALID_DELAY_US. We don't need to
 * add such delay every time RSSI value is needed. If the Carier Sense signal
 * is high or CCA signal is high, we know that the RSSI value must be valid.
 * We use that knowledge to reduce our wait time. We break down the delay loop
 * in multiple chunks and during each iteration, check for the CS and CCA
 * signal. If either of these signals is high, we return immediately. Else,
 * we wait for the max delay specified.
 */
#define CC1100_RSSI_VALID_WAIT()                                                \
{                                                                             \
  INT16S delay = CC1100_RSSI_VALID_DELAY_US;                                   \
  do                                                                          \
  {                                                                           \
    if(CC1100_halRfReadStatusReg(CC1100_PKTSTATUS) & (CC1100_PKTSTATUS_CCA | CC1100_PKTSTATUS_CS))  \
    {                                                                         \
      break;                                                                  \
    }                                                                         \
    CC1100_DelayUsec(64); /* sleep */                                           \
    delay -= 64;                                                              \
  }while(delay > 0);                                                          \
}

#define CC1100_SPI_DRIVE_CSN_LOW()                   MCU_IO_CLR(IO_SPI_CSN_PORT,IO_SPI_CSN_PIN)
#define CC1100_SPI_DRIVE_CSN_HIGH()                  MCU_IO_SET(IO_SPI_CSN_PORT,IO_SPI_CSN_PIN)
#define CC1100_SPI_SO_IS_HIGH()                      MCU_IO_GET(IO_SPI_MISO_PORT,IO_SPI_MISO_PIN)
#define CC1100_SPI_CSN_IS_HIGH()                     MCU_IO_GET(IO_SPI_CSN_PORT, IO_SPI_CSN_PIN)



//----------------------------------------------------------------------------------
//  Variables used in this file
//----------------------------------------------------------------------------------
static volatile INT8U  packetComplete;
static volatile INT8U  txStrobeNeeded   = TRUE;
static volatile INT8U  nPacketsPending  = 0;
static volatile INT16U nBytesInFifo     = 0;

static INT8U cc1100_RadioState  = CC1100_RADIO_STATE_UNKNOWN;
static INT8U cc1100_RndSeed;

static volatile INT8U  sReplyDelayContext;
static volatile INT8U  sKillSem;
static          INT16U sReplyDelayScalar;
static          INT16U sBackoffHelper;

static void CC1100_RxModeOn(void);
static void CC1100_RxModeOff(void);
static void CC1100_TxModeOn(void);
static void CC1100_TxModeOff(void);
static void CC1100_DelayUsec(INT16U howLong);
static void CC1100_RandomBackoffDelay(void);

void  CC1100_TxOn(void);
void  CC1100_RxOn(void);
void  CC1100_RxIdle(void);
void  CC1100_TxIdle(void);
void  CC1100_Sleep(void);
void  CC1100_WakeUp(void);
INT8U CC1100_RandomByte(void);
INT8S CC1100_CalculateRssi(INT8U rawValue);
void  CC1100_rxPacketRecvd(void);
void  CC1100_SetLogicalChannel(INT8U chan);
INT8U CC1100_GetRadioState(void);
/**************************************************************************************************
 * @fn          CC1100_Init
 *
 * @brief       Initialize CC1100.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_Init(void)
{
   /* ------------------------------------------------------------------
   *    Initialization
   *   -----------------
   */

  /* initialize GPIO pins */
  CC1100_CONFIG_GDO0_PIN_AS_INPUT();


  /* initialize SPI */
  halIOSpiInit(0);

  /* ------------------------------------------------------------------
   *    Radio power-up reset
   *   ----------------------
   */
  CC1100_halRfResetChip();



  /* initialize radio registers */
  CC1100_halRfConfig(&CC1100_RfConfig,CC1100_PaTable,CC1100_PaTableLth);

  /*personal radio registers setting*/
  CC1100_halRfWriteReg(CC1100_MCSM1,   CC1100_SETTING_MCSM1);

  /* Initial radio state is IDLE state */
  cc1100_RadioState = CC1100_RADIO_STATE_IDLE;

  /* set default channel */
  CC1100_SetLogicalChannel( 0 );

  /* Generate Random seed:
   * We will use the RSSI value to generate our random seed.
   */

  /* Put the radio in RX state */
  CC1100_halRfStrobe( CC1100_SRX );

  /* delay for the rssi to be valid */
  CC1100_RSSI_VALID_WAIT();

  /* use most random bit of rssi to populate the random seed */
  for(INT8U i=0; i<16; i++)
  {
    cc1100_RndSeed = (cc1100_RndSeed << 1) | (CC1100_halRfReadReg(CC1100_RSSI) & 0x01);
  }

  /* Force the seed to be non-zero by setting one bit, just in case... */
  cc1100_RndSeed |= 0x0080;

  /* Turn off RF. */
  CC1100_RxModeOff();
  /*****************************************************************************************
   *                            Compute reply delay scalar
   *
   * Formula from data sheet for all the narrow band radios is:
   *
   *                (256 + DATAR_Mantissa) * 2^(DATAR_Exponent)
   * DATA_RATE =    ------------------------------------------ * f(xosc)
   *                                    2^28
   *
   * To try and keep some accuracy we change the exponent of the denominator
   * to (28 - (exponent from the configuration register)) so we do a division
   * by a smaller number. We find the power of 2 by shifting.
   *
   * The maximum delay needed depends on the MAX_APP_PAYLOAD parameter. Figure
   * out how many bits that will be when overhead is included. Bits/bits-per-second
   * is seconds to transmit (or receive) the maximum frame. We multiply this number
   * by 1000 to find the time in milliseconds. We then additionally multiply by
   * 10 so we can add 5 and divide by 10 later, thus rounding up to the number of
   * milliseconds. This last won't matter for slow transmissions but for faster ones
   * we want to err on the side of being conservative and making sure the radio is on
   * to receive the reply. The semaphore monitor will shut it down. The delay adds in
   * a fudge factor that includes processing time on peer plus lags in Rx and processing
   * time on receiver's side.
   *
   * Note that we assume a 26 MHz clock for the radio...
   * ***************************************************************************************
   */
#define   CC1100_RADIO_OSC_FREQ         26000000
#define   PLATFORM_FACTOR_CONSTANT    2
#define   PHY_PREAMBLE_SYNC_BYTES     8

  {
    INT32U dataRate, bits;
    INT16U exponent, mantissa;

    /* mantissa is in MDMCFG3 */
    mantissa = 256 +  CC1100_RfConfig.mdmcfg3;

    /* exponent is lower nibble of MDMCFG4. */
    exponent = 28 - (CC1100_RfConfig.mdmcfg4 & 0x0F);

    /* we can now get data rate */
    dataRate = mantissa * (CC1100_RADIO_OSC_FREQ>>exponent);

    bits = ((INT32U)((PHY_PREAMBLE_SYNC_BYTES + CC1100_MAX_PACKET_SIZE)*8))*10000;

    /* processing on the peer + the Tx/Rx time plus more */
    sReplyDelayScalar = PLATFORM_FACTOR_CONSTANT + (((bits/dataRate)+5)/10);

    /* This helper value is used to scale the backoffs during CCA. At very
     * low data rates we need to backoff longer to prevent continual sampling
     * of valid frames which take longer to send at lower rates. Use the scalar
     * we just calculated divided by 32. With the backoff algorithm backing
     * off up to 16 periods this will result in waiting up to about 1/2 the total
     * scalar value. For high data rates this does not contribute at all. Value
     * is in microseconds.
     */
    sBackoffHelper = CC1100_BACKOFF_PERIOD_USECS + (sReplyDelayScalar>>5)*1000;
  }
  /* ------------------------------------------------------------------
   *    Configure interrupts
   *   ----------------------
   */

  /*
   *  Configure and enable the SYNC signal interrupt.
   *
   *  This interrupt is used to indicate receive.  The SYNC signal goes
   *  high when a receive OR a transmit begins.  It goes high once the
   *  sync word is received or transmitted and then goes low again once
   *  the packet completes.
   */
  CC1100_CONFIG_GDO0_AS_SYNC_SIGNAL();
  CC1100_CONFIG_SYNC_PIN_FALLING_EDGE_INT();
  CC1100_CLEAR_SYNC_PIN_INT_FLAG();

  // Set up interrupt on GDO0
  MCU_IO_SET(CC1100_GDO0_PORT,CC1100_GDO0_PIN);
  MCU_IO_INPUT(CC1100_GDO0_PORT,CC1100_GDO0_PIN);

  CC1100_CONFIG_GDO2_PIN_AS_INPUT();
  CC1100_CONFIG_GDO2_AS_CS_SIGNAL();

  halExtIntConnect(CC1100_GDO0_INT,&CC1100_rxPacketRecvd);
  halExtIntEnable(CC1100_GDO0_INT);

}
//----------------------------------------------------------------------------------
//  void CC1100_rxFifoHalfFull(void)
//
//  DESCRIPTION:
//    This function is called when the FIFO Threshold signal is asserted, indicating
//    that the FIFO (in this example) is half full. Set a flag indicating that there
//    is data in the FIFO.
//----------------------------------------------------------------------------------
void CC1100_rxFifoHalfFull(void)
{

}


//----------------------------------------------------------------------------------
//  void CC1100_rxPacketRecvd(void)
//
//  DESCRIPTION:
//    This function is called when a complete packet has been received. Set a flag
//    indicating that radio has received a complete packet.
//----------------------------------------------------------------------------------
void CC1100_rxPacketRecvd(void)
{
    packetComplete = TRUE;
}


//----------------------------------------------------------------------------------
//  void CC1100_rxInit(void)
//
//  DESCRIPTION:
//    Set up chip to operate in RX mode
//----------------------------------------------------------------------------------
void CC1100_rxInit(void)
{

    // Set GDO0 to be be packet received signal
    CC1100_halRfWriteReg(CC1100_IOCFG0, 0x06);

    // Set up interrupt on GDO0
    MCU_IO_SET(CC1100_GDO0_PORT,CC1100_GDO0_PIN);
    MCU_IO_INPUT(CC1100_GDO0_PORT,CC1100_GDO0_PIN);
    halExtIntSetType(CC1100_GDO0_INT, HAL_EXT_INT_FALLING_EDGE);
    halExtIntConnect(CC1100_GDO0_INT, &CC1100_rxPacketRecvd);
    halExtIntEnable(CC1100_GDO0_INT);

}


//----------------------------------------------------------------------------------
//  INT8U CC1100_rxRecvPacket(INT8U* data, INT8U* length , INT8U* rssi)
//
//  DESCRIPTION:
//    Receive packet from radio. Waits for either a FIFO half full event or
//    a packet received event and reads data from the RX FIFO accordingly.
//    Returns when a complete packet is received.
//
//  ARGUMENTS:
//    data    - Pointer to where to write the incoming packet payload
//    length  - Pointer to where to write the length of the packet payload
//
//  RETURNS:
//    CC1100_RX_OK                - packet was received successfully
//    CC1100_RX_LENGTH_VIOLATION  - length of the packet is illegal
//    CC1100_RX_CRC_MISMATCH      - claculated CRC does not match packet CRC
//    CC1100_RX_NO_DATA           - no data received
//----------------------------------------------------------------------------------
INT8U CC1100_rxRecvPacket(INT8U* data, INT8U* length, INT8U* rssi)
{
    INT8U done = FALSE;
    INT8U s;
    INT8U rxBytes;

    if(CC1100_RADIO_STATE_RX != cc1100_RadioState)
      return(CC1100_RX_MODE_ERR);
    // Reset state and set radio in RX mode
    // Safe to set states, as radio is IDLE
    /*
    static INT8U CC1100_Chip_State;
    CC1100_Chip_State = CC1100_halRfReadStatusReg(CC1100_MARCSTATE)&0x1f;
    switch(CC1100_Chip_State)
    {
        case  CC1100_MARC_STATE_RXFIFO_OVERFLOW:
                CC1100_halRfStrobe( CC1100_SIDLE );
                while (CC1100_halRfStrobe( CC1100_SNOP ) & 0xF0) ;
                CC1100_halRfStrobe(CC1100_SIDLE);
            CC1100_halRfStrobe(CC1100_SFRX);
                return(CC1100_RX_LENGTH_VIOLATION);
            break;
        case  CC1100_MARC_STATE_IDLE:
                CC1100_halRfStrobe(CC1100_SRX);
                break;
    }
    */

    while (!done)
    {
        // Wait for further action
        // Be careful here. This is actually a critical section. If you get
        // the interrupt AFTER checking the two booleans, but BEFORE setting
        // the low power mode, you might get stuck!

        if (!packetComplete)
        {

            return(CC1100_RX_NO_DATA);
        }
        /*
         *  Read the RXBYTES register from the radio.
         *  Bit description of RXBYTES register:
         *    bit 7     - RXFIFO_OVERFLOW, set if receive overflow occurred
         *    bits 6:0  - NUM_BYTES, number of bytes in receive FIFO
         *
         *  Due a chip bug, the RXBYTES register must read the same value twice
         *  in a row to guarantee an accurate value.
         */
         {
            INT8U rxBytesVerify;

            rxBytesVerify = CC1100_halRfReadReg( CC1100_RXBYTES );

            do
            {
               rxBytes = rxBytesVerify;
               rxBytesVerify = CC1100_halRfReadReg( CC1100_RXBYTES );
            }
            while (rxBytes != rxBytesVerify);
          }
        if (rxBytes == 0)
        {
           /* receive FIFO is empty - do nothing, skip to end */
           return(CC1100_RX_NO_DATA);
        }
        // An interrupt has occured. Take the appropriate action
        // according to the state of the system.
        if (packetComplete)
        {
            HAL_INT_LOCK(s);

            packetComplete = FALSE;

            HAL_INT_UNLOCK(s);

            CC1100_halRfReadFifo(length, 1);

            if (*length == 0 || *length > CC1100_MAX_PACKET_SIZE)
            {
                CC1100_halRfStrobe(CC1100_SIDLE);
                CC1100_halRfStrobe(CC1100_SFRX);
                CC1100_halRfStrobe(CC1100_SRX);
                return(CC1100_RX_LENGTH_VIOLATION);
            }

            // Get the complete packet from the FIFO
            CC1100_halRfReadFifo(data, *length);
            done = TRUE;
        }
    }

    // Get the appended status bytes [RSSI, LQI]
    CC1100_halRfReadFifo(rssi, 2);


    // Check CRC
    if ((rssi[1] & CC1100_LQI_CRC_OK_BM) != CC1100_LQI_CRC_OK_BM)
    {
        return(CC1100_RX_CRC_MISMATCH);
    }
    return(CC1100_RX_OK);
}


//----------------------------------------------------------------------------------
//  void  CC1100_halRfChangeTxPower(INT8U TxPower)
//
//  DESCRIPTION:
//    Used to set CC1100 tx power
//  ARGUMENTS:
//    TxPower     - tx power (adefine as value below)
//    CC1100_TX_PA_10DBM          0xC2
//    CC1100_TX_PA_7DBM           0xCB
//    CC1100_TX_PA_5DBM           0x85
//    CC1100_TX_PA_0DBM           0x60
//    CC1100_TX_PA__5DBM          0x57
//    CC1100_TX_PA__10DBM         0x26
//    CC1100_TX_PA__15DBM         0x1D
//    CC1100_TX_PA__20DBM         0x17
//    CC1100_TX_PA__30DBM         0x04
//
//----------------------------------------------------------------------------------
void  CC1100_halRfChangeTxPower(INT8U TxPower)
{
   CC1100_halRfWriteReg(CC1100_PATABLE | CC1100_WRITE_BURST,TxPower);
}

//----------------------------------------------------------------------------------
//  void  CC1100_halRfChangeChannel(INT8U ChannelNo)
//
//  DESCRIPTION:
//    Used to set CC1100 Channel
//  ARGUMENTS:
//    ChannelNo     - Channel(0-255)
//
//----------------------------------------------------------------------------------
void  CC1100_halRfChangeChannel(INT8U ChannelNo)
{
   CC1100_halRfWriteReg(CC1100_CHANNR,ChannelNo);
}


//----------------------------------------------------------------------------------
//  void CC1100_txFifoHalfFull(void)
//
//  DESCRIPTION:
//    This function is called when the FIFO Threshold signal is deasserted, indicating
//    that the FIFO (in this example) is half full. Update the number of bytes
//    that are in the FIFO.
//----------------------------------------------------------------------------------
static void CC1100_txFifoHalfFull(void)
{

}

/**************************************************************************************************
 * @fn          CC1100_Transmit
 *
 * @brief       Transmit a packet using CCA algorithm.
 *
 * @param       pPacket - pointer to packet to transmit
 *
 * @return      Return code indicates success or failure of transmit:
 *                  CC1100_TX_RESULT_SUCCESS - transmit succeeded
 *                  CC1100_TX_RESULT_FAILED  - transmit failed because CCA failed
 **************************************************************************************************
 */
INT8U CC1100_Transmit(INT8U* data, INT8U length, INT8U txType)
{
  INT8U ccaRetries;
  INT8U returnValue = CC1100_TX_RESULT_SUCCESS;

  /* radio must be awake to transmit */
  CC1100_ASSERT( cc1100_RadioState != CC1100_RADIO_STATE_OFF );

  /* Turn off reciever. We can ignore/drop incoming packets during transmit. */
  CC1100_RxModeOff();



  /* ------------------------------------------------------------------
   *    Write packet to transmit FIFO
   *   --------------------------------
   */

  CC1100_halRfWriteFifo(data, length);


  /* ------------------------------------------------------------------
   *    Immediate transmit
   *   ---------------------
   */
  if (txType == CC1100_TX_TYPE_FORCED)
  {
    /* Issue the TX strobe. */
    CC1100_halRfStrobe( CC1100_STX );

    /* Wait for transmit to complete */
    while(!CC1100_SYNC_PIN_INT_FLAG_IS_SET());

    /* Clear the interrupt flag */
    CC1100_CLEAR_SYNC_PIN_INT_FLAG();
  }
  else if (txType == CC1100_TX_TYPE_RANDOM)
  {
    /*Random Back off send frame*/
    CC1100_RandomBackoffDelay();
    /* Issue the TX strobe. */
    CC1100_halRfStrobe( CC1100_STX );

    /* Wait for transmit to complete */
    while(!CC1100_SYNC_PIN_INT_FLAG_IS_SET());

    /* Clear the interrupt flag */
    CC1100_CLEAR_SYNC_PIN_INT_FLAG();
  }
  else
  {
    /* ------------------------------------------------------------------
     *    CCA transmit
     *   ---------------
     */

    CC1100_ASSERT( txType == CC1100_TX_TYPE_CCA );

    /* set number of CCA retries */
    ccaRetries = CC1100_CCA_RETRIES;

    /* For CCA algorithm, we need to know the transition from the RX state to
     * the TX state. There is no need for SYNC signal in this logic. So we
     * can re-configure the GDO_0 output from the radio to be PA_PD signal
     * instead of the SYNC signal.
     * Since both SYNC and PA_PD are used as falling edge interrupts, we
     * don't need to reconfigure the MCU input.
     */

    CC1100_CONFIG_GDO0_AS_PAPD_SIGNAL();


    /* ===============================================================================
     *    Main Loop
     *  =============
     */
    for (;;)
    {
      /* Radio must be in RX mode for CCA to happen.
       * Otherwise it will transmit without CCA happening.
       */

      /* Can not use the CC1100_RxModeOn() function here since it turns on the
       * Rx interrupt, which we don't want in this case.
       */

      CC1100_halRfStrobe( CC1100_SRX );

      /* wait for the rssi to be valid. */
      CC1100_RSSI_VALID_WAIT();

      /*
       *  Clear the PA_PD pin interrupt flag.  This flag, not the interrupt itself,
       *  is used to capture the transition that indicates a transmit was started.
       *  The pin level cannot be used to indicate transmit success as timing may
       *  prevent the transition from being detected.  The interrupt latch captures
       *  the event regardless of timing.
       */
      CC1100_CLEAR_PAPD_PIN_INT_FLAG();

      /* send strobe to initiate transmit */
      CC1100_halRfStrobe( CC1100_STX );

      /* Delay long enough for the PA_PD signal to indicate a
       * successful transmit. This is the 250 XOSC periods
       * (9.6 us for a 26 MHz crystal) See section 19.6 of 2500 datasheet.
       * Found out that we need a delay of atleast 20 us on CC2500 and
       * 25 us on CC1100 to see the PA_PD signal change.
       */
       CC1100_DelayUsec(25);

      /* PA_PD signal goes from HIGH to LOW when going from RX state.
       * This transition is trapped as a falling edge interrupt flag
       * to indicate that CCA passed and the transmit has started.
       */
      if (CC1100_PAPD_INT_FLAG_IS_SET())
      {
        /* ------------------------------------------------------------------
        *    Clear Channel Assessment passed.
        *   ----------------------------------
        */

        /* Clear the PA_PD int flag */
        CC1100_CLEAR_PAPD_PIN_INT_FLAG();

        /* PA_PD signal stays LOW while in TX state and goes back to HIGH when
         * the radio transitions to RX state.
         */
        /* wait for transmit to complete */
        while (!CC1100_PAPD_PIN_IS_HIGH());
        //INT8U CC2500_TxState = CC1100_halRfReadStatusReg(CC1100_MARCSTATE)&0x1f;
        //if(CC2500_TxState == CC1100_MARC_STATE_TX)
        /* transmit done, break */
        break;
       }
      else
      {
        /* ------------------------------------------------------------------
         *    Clear Channel Assessment failed.
         *   ----------------------------------
         */

        /* Turn off radio and save some power during backoff */

        /* NOTE: Can't use CC1100_RxModeOff() - since it tries to update the
         * sync signal status which we are not using during the TX operation.
         */
        CC1100_STROBE_IDLE_AND_WAIT();

        /* flush the receive FIFO of any residual data */
        CC1100_halRfStrobe( CC1100_SFRX );

        //CC1100_halRfStrobe( CC1100_SFTX );
        /* Retry ? */
        if (ccaRetries != 0)
        {
          /* delay for a random number of backoffs */
          CC1100_RandomBackoffDelay();

          /* decrement CCA retries before loop continues */
          ccaRetries--;
        }
        else /* No CCA retries are left, abort */
        {
          /* set return value for failed transmit and break */
          returnValue = CC1100_TX_RESULT_FAILED;
          break;
        }
      } /* CCA Failed */
    } /* CCA loop */
  }/* txType is CCA */

  /* Done with TX. Clean up time... */

  /* Radio is already in IDLE state */

  /*
   * Flush the transmit FIFO.  It must be flushed so that
   * the next transmit can start with a clean slate.
   */
  CC1100_halRfStrobe( CC1100_SFTX );

  /* Restore GDO_0 to be SYNC signal */
  CC1100_CONFIG_GDO0_AS_SYNC_SIGNAL();

  /* If the radio was in RX state when transmit was attempted,
   * put it back to Rx On state.
   */
  if(cc1100_RadioState == CC1100_RADIO_STATE_RX)
  {
    CC1100_RxModeOn();
  }

  return( returnValue );
}
//----------------------------------------------------------------------------------
//  void CC1100_txPacketSent(void)
//
//  DESCRIPTION:
//    This function is called every time the radio indicates that a packet has
//    been transmitted. Get the number of bytes in the FIFO and strobe TX if
//    there are packets to be sent.
//----------------------------------------------------------------------------------
static void CC1100_txPacketSent(void)
{
    nPacketsPending--;

    // Get number of bytes in TXFIFO.
    // Note the CC1100/CC1100 errata concerning reading from the TXBYTES
    // register. However, since a packet has been transmitted, the radio
    // is no longer in TX state, since (in this particular application),
    // MCSM1.TXOFF_MODE is set to IDLE.
    nBytesInFifo = CC1100_halRfReadStatusReg(CC1100_TXBYTES);

    if (nBytesInFifo & 0x80)
    {
      // Oops! TX underflow. There is something seriously wrong
        // Don't try to do anything more.
      CC1100_halRfStrobe(CC1100_SIDLE);
      CC1100_halRfStrobe(CC1100_SFTX);
      txStrobeNeeded = TRUE;
    }

    if (nPacketsPending > 0 && nBytesInFifo > 0)
    {
        txStrobeNeeded = FALSE;
        CC1100_halRfStrobe(CC1100_STX);
    }
    else
    {
        txStrobeNeeded = TRUE;
    }
}


//----------------------------------------------------------------------------------
//  void CC1100_txInit(void)
//
//  DESCRIPTION:
//    Set up chip to operate in TX mode
//----------------------------------------------------------------------------------
void CC1100_txInit(void)
{

    // Set GDO0 to be packet sent signal
    CC1100_halRfWriteReg(CC1100_IOCFG0, 0x06);

    // Set up interrupt on GDO0
    halExtIntSetType(CC1100_GDO0_INT, HAL_EXT_INT_FALLING_EDGE);
    halExtIntConnect(CC1100_GDO0_INT, &CC1100_txPacketSent);
    halExtIntEnable(CC1100_GDO0_INT);

}


//----------------------------------------------------------------------------------
//  INT8U CC1100_txSendPacket(INT8U* data, INT8U length)
//
//  DESCRIPTION:
//    Send a packet over the air. Use flow control features of the CC1100/CC1100
//    to regulate the number of bytes that can be wirtten to the FIFO at ony time.
//    Return once the packet has been written to the FIFO (i.e. don't wait for the
//    packet to actually be sent).
//
//  ARGUMENTS:
//    data   - Data to send. First byte contains length byte
//    length - Total length of packet to send
//
//  RETURNS:
//    This function always returns 0.
//
//----------------------------------------------------------------------------------
INT8U CC1100_txSendPacket(INT8U* data, INT8U length)
{
    INT8U bytesRemaining = (INT8U)length;
    INT8U bytesWritten   = 0;
    INT8U bytesToWrite;
    INT8U key;

    if(CC1100_RADIO_STATE_TX != cc1100_RadioState)
      return(CC1100_TX_MODE_ERR);

    HAL_INT_LOCK(key);

    nPacketsPending++;

    HAL_INT_UNLOCK(key);

    while (bytesRemaining > 0)
    {
        HAL_INT_LOCK(key);

        bytesToWrite = MIN(CC1100_MAX_PACKET_SIZE - nBytesInFifo, bytesRemaining);

        if (bytesToWrite == 0)
        {
            nPacketsPending--;
            HAL_INT_UNLOCK(key);
            return (CC1100_TX_FIFO_FULL);
        }
        else
        {
            // Write data fragment to FIFO
            nBytesInFifo += bytesToWrite;
            HAL_INT_UNLOCK(key);
            CC1100_halRfWriteFifo(&data[bytesWritten], bytesToWrite);

            bytesWritten   += bytesToWrite;
            bytesRemaining -= bytesToWrite;
            if (txStrobeNeeded)
            {
                HAL_INT_LOCK(key);

                txStrobeNeeded = FALSE;

                HAL_INT_UNLOCK(key);
                CC1100_halRfStrobe(CC1100_STX);
            }
        }
    }
    return(0);
}

/**************************************************************************************************
 * @fn          CC1100_CalculateRssi
 *
 * @brief       Does binary to decimal conversiont and offset compensation.
 *
 * @param       none
 *
 * @return      RSSI value in units of dBm.
 **************************************************************************************************
 */
INT8S CC1100_CalculateRssi(INT8U rawValue)
{
  INT16S rssi;

  /* The raw value is in 2's complement and in half db steps. Convert it to
   * decimal taking into account the offset value.
   */
  if(rawValue >= 128)
  {
    rssi = (INT16S)(rawValue - 256)/2 - CC1100_RSSI_OFFSET;
  }
  else
  {
    rssi = (rawValue/2) - CC1100_RSSI_OFFSET;
  }

  /* Restrict this value to least value can be held in an 8 bit signed int */
  if(rssi < -128)
  {
    rssi = -128;
  }

  return rssi;
}

/**************************************************************************************************
 * @fn          CC1100_SetLogicalChannel
 *
 * @brief       Set logical channel.
 *
 * @param       chan - logical channel number
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_SetLogicalChannel(INT8U chan)
{

  /* make sure radio is off before changing channels */
  CC1100_RxModeOff();


  CC1100_halRfWriteReg(CC1100_CHANNR | CC1100_WRITE_BURST,chan);
  /* turn radio back on if it was on before channel change */
  if(cc1100_RadioState == CC1100_RADIO_STATE_RX)
  {
    CC1100_RxModeOn();
  }
}

void  CC1100_SetTxPower(INT8U TxPower)
{
    CC1100_halRfChangeTxPower(TxPower);
}

/**************************************************************************************************
 * @fn          CC1100_RxModeOn
 *
 * @brief       Put radio into receive mode.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
static void CC1100_RxModeOn(void)
{

  /* clear any residual receive interrupt */
  CC1100_CLEAR_SYNC_PIN_INT_FLAG();


  /* send strobe to enter receive mode */
  CC1100_halRfStrobe( CC1100_SRX );
  halExtIntConnect(CC1100_GDO0_INT, &CC1100_rxPacketRecvd);


  /* enable receive interrupts */
  CC1100_ENABLE_SYNC_PIN_INT();
}

/**************************************************************************************************
 * @fn          CC1100_RxOn
 *
 * @brief       Turn on the receiver.  No harm is done if this function is called when
 *              receiver is already on.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_RxOn(void)
{
  /* radio must be awake before we can move it to RX state */
  CC1100_ASSERT( cc1100_RadioState != CC1100_RADIO_STATE_OFF );

  /* if radio is off, turn it on */
  if(cc1100_RadioState != CC1100_RADIO_STATE_RX)
  {

    cc1100_RadioState = CC1100_RADIO_STATE_RX;

    CC1100_RxModeOn();
  }
}
/**************************************************************************************************
 * @fn          CC1100_TxModeOn
 *
 * @brief       Put radio into receive mode.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
static void CC1100_TxModeOn(void)
{
  /* clear any residual receive interrupt */
  CC1100_CLEAR_SYNC_PIN_INT_FLAG();


  /* send strobe to enter receive mode */
  halExtIntConnect(CC1100_GDO0_INT, &CC1100_txPacketSent);

  /* enable receive interrupts */
  CC1100_ENABLE_SYNC_PIN_INT();
}

/**************************************************************************************************
 * @fn          CC1100_TxModeOff
 *
 * @brief       -
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
static void CC1100_TxModeOff(void)
{
  /*disable receive interrupts */
  CC1100_DISABLE_SYNC_PIN_INT();

  /* turn off radio */
  CC1100_STROBE_IDLE_AND_WAIT();

  /* flush the receive FIFO of any residual data */
  CC1100_halRfStrobe( CC1100_SFTX );

  /* clear receive interrupt */
  CC1100_CLEAR_SYNC_PIN_INT_FLAG();
}
/**************************************************************************************************
 * @fn          CC1100_TxOn
 *
 * @brief       Turn on the tansmiter.  No harm is done if this function is called when
 *              tansmiter is already on.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_TxOn(void)
{
  /* radio must be awake before we can move it to RX state */
  CC1100_ASSERT( cc1100_RadioState != CC1100_RADIO_STATE_OFF );

  /* if radio is off, turn it on */
  if(cc1100_RadioState != CC1100_RADIO_STATE_TX)
  {
    cc1100_RadioState = CC1100_RADIO_STATE_TX;
    CC1100_TxModeOn();
  }
}

/**************************************************************************************************
 * @fn          CC1100_RxModeOff
 *
 * @brief       -
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
static void CC1100_RxModeOff(void)
{
  /*disable receive interrupts */
  CC1100_DISABLE_SYNC_PIN_INT();

  /* turn off radio */
  CC1100_STROBE_IDLE_AND_WAIT();

  /* flush the receive FIFO of any residual data */
  CC1100_halRfStrobe( CC1100_SFRX );

  /* clear receive interrupt */
  CC1100_CLEAR_SYNC_PIN_INT_FLAG();
}


/**************************************************************************************************
 * @fn          CC1100_RxIdle
 *
 * @brief       Put radio in idle mode (receiver if off).  No harm is done this function is
 *              called when radio is already idle.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_RxIdle(void)
{
  /* radio must be awake to move it to idle mode */
  CC1100_ASSERT( cc1100_RadioState != CC1100_RADIO_STATE_OFF );


  /* if radio is on, turn it off */
  if(cc1100_RadioState == CC1100_RADIO_STATE_RX)
  {
    CC1100_RxModeOff();

    cc1100_RadioState = CC1100_RADIO_STATE_IDLE;

  }
}

/**************************************************************************************************
 * @fn          CC1100_TxIdle
 *
 * @brief       Put radio in idle mode (receiver if off).  No harm is done this function is
 *              called when radio is already idle.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_TxIdle(void)
{
  /* radio must be awake to move it to idle mode */
  CC1100_ASSERT( cc1100_RadioState != CC1100_RADIO_STATE_OFF );

  /* wait current sent over */
  while(nPacketsPending);

  /* if radio is on, turn it off */
  if(cc1100_RadioState == CC1100_RADIO_STATE_TX)
  {
    CC1100_TxModeOff();
    cc1100_RadioState = CC1100_RADIO_STATE_IDLE;
  }
}
/**************************************************************************************************
 * @fn          CC1100_Sleep
 *
 * @brief       Request radio go to sleep.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_Sleep(void)
{

  /* Critical section necessary for watertight testing and
   * setting of state variables.
   */

  /* If radio is not asleep, put it to sleep */
  if(cc1100_RadioState != CC1100_RADIO_STATE_OFF)
  {
    /* go to idle so radio is in a known state before sleeping */
    CC1100_RxIdle();

    CC1100_halRfStrobe( CC1100_SPWD );

    /* Our new state is OFF */
    cc1100_RadioState = CC1100_RADIO_STATE_OFF;
  }

}


/**************************************************************************************************
 * @fn          CC1100_WakeUp
 *
 * @brief       Wake up radio from sleep state.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void CC1100_WakeUp(void)
{
  /* if radio is already awake, just ignore wakeup request */
  if(cc1100_RadioState != CC1100_RADIO_STATE_OFF)
  {
    return;
  }

  /* drive CSn low to initiate wakeup */
  CC1100_SPI_DRIVE_CSN_LOW();

  /* wait for MISO to go high indicating the oscillator is stable */
  while (CC1100_SPI_SO_IS_HIGH());

  /* wakeup is complete, drive CSn high and continue */
  CC1100_SPI_DRIVE_CSN_HIGH();


  /* enter idle mode */
  cc1100_RadioState = CC1100_RADIO_STATE_IDLE;
  CC1100_STROBE_IDLE_AND_WAIT();
}

/**************************************************************************************************
 * @fn          CC1100_GetRadioState
 *
 * @brief       Returns the current radio state.
 *
 * @param       none
 *
 * @return      radio state - off/idle/rx
 **************************************************************************************************
 */
INT8U CC1100_GetRadioState(void)
{
  return cc1100_RadioState;
}

/****************************************************************************************************
 * @fn          CC1100_DelayUsec
 *
 * @brief       Execute a delay loop using HW timer. The macro actually used to do the delay
 *              is not thread-safe. This routine makes the delay execution thread-safe by breaking
 *              up the requested delay up into small chunks and executing each chunk as a critical
 *              section. The chunk size is choosen to be the smallest value used by CC1100. The delay
 *              is only approximate because of the overhead computations. It errs on the side of
 *              being too long.
 *
 * input parameters
 * @param   howLong - number of microseconds to delay
 *
 * @return      none
 ****************************************************************************************************
 */
static void CC1100_DelayUsec(INT16U howLong)
{
  INT8U s;
  INT16U count = howLong/CC1100_MAX_DELAY_US;

  if (howLong)
  {
    do
    {
      HAL_INT_LOCK(s);
      DELAY_US(CC1100_MAX_DELAY_US);
      HAL_INT_UNLOCK(s);
    } while (count--);
  }

  return;
}
/**************************************************************************************************
 * @fn          CC1100_RandomByte
 *
 * @brief       Returns a random byte. This is a pseudo-random number generator.
 *              The generated sequence will repeat every 256 values.
 *              The sequence itself depends on the initial seed value.
 *
 * @param       none
 *
 * @return      a random byte
 **************************************************************************************************
 */
INT8U CC1100_RandomByte(void)
{
  cc1100_RndSeed = (cc1100_RndSeed*CC1100_RANDOM_MULTIPLIER) + CC1100_RANDOM_OFFSET;

  return cc1100_RndSeed;
}
/**************************************************************************************************
 * @fn          CC1100_RandomBackoffDelay
 *
 * @brief       -
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
static void CC1100_RandomBackoffDelay(void)
{
  INT8U backoffs;
  INT8U i;

  /* calculate random value for backoffs - 1 to 16 */
  backoffs = (CC1100_RandomByte() & 0x0F) + 1;

  /* delay for randomly computed number of backoff periods */
  for (i=0; i<backoffs; i++)
  {
    CC1100_DelayUsec( sBackoffHelper );
  }
}